package com.crawler.html.impl;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.logging.Level;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.crawler.dto.Parameter;
import com.crawler.dto.ProxyOneself;
import com.crawler.html.WebSite;
import com.crawler.util.CodeCharge;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.ThreadedRefreshHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlImage;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.google.common.base.Strings;

public class TX_Site implements WebSite {
    private Logger log = Logger.getLogger(TX_Site.class);
    private String url = "http://www.tianxun.com";
    private WebClient webClient;
    private HtmlPage page;
    private Parameter parameter;
    private Code codeO;
    private ProxyOneself proxy;

    public TX_Site() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
        this.parameter = new Parameter();
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log",
                "org.apache.commons.logging.impl.NoOpLog");
        java.util.logging.Logger.getLogger("com.gargoylesoftware.htmlunit").setLevel(Level.OFF);
        java.util.logging.Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.OFF);

        // 初始化模拟浏览器设置
        webClient = new WebClient(BrowserVersion.INTERNET_EXPLORER_11);
    }

    @Override
    public WebSite setParameter(Parameter parameter) {
        this.parameter = parameter;
        return this;
    }

    @Override
    public WebSite enterCodeManually() throws IOException {
        class CodeImpl implements Code {
            @Override
            public void enterCode() throws IOException {
                final HtmlImage image = (HtmlImage) page.getElementById("captchaImg");
                parameter.setRandCode((String) JOptionPane.showInputDialog(null, "" + "验证码:", "验证码",
                        JOptionPane.NO_OPTION, new ImageIcon(image.getImageReader().read(0)), null, null));
                ((HtmlInput) page.getElementById("captcha")).setValueAttribute(parameter.getRandCode());
                page = ((HtmlAnchor) page.getElementById("submitBtn")).click();
                if(page.getTitleText().equals("访问异常")){
                    enterCode();
                }
            }

        }
        this.codeO = new CodeImpl();
        return this;
    }

    @Override
    public WebSite enterCodeCharge() throws IOException {
        class CodeImpl implements Code {
            @Override
            public void enterCode() throws IOException {
                final HtmlImage image = (HtmlImage) page.getElementById("captchaImg");
                BufferedImage read = image.getImageReader().read(0);
                String res = CodeCharge.enterCodeCharge(read,proxy);
                if (!Strings.isNullOrEmpty(res))
                    parameter.setRandCode(res);
                ((HtmlInput) page.getElementById("captcha")).setValueAttribute(parameter.getRandCode());
                page = ((HtmlAnchor) page.getElementById("submitBtn")).click();
                if(page.getTitleText().equals("访问异常")){
                    enterCode();
                }
            }
        }
        this.codeO = new CodeImpl();
        return this;
    }

    private void getSession_Token() {
//        System.out.println(page.asXml());
        String text = page.asXml().replaceAll("\r|\n", "");
        int start = text.indexOf("var PARAMS = ") + "var PARAMS = ".length();
        text = text.substring(start, text.indexOf("}", start) + 1);
        this.parameter.setSessionKey(JSONObject.parseObject(text).getString("sessionKey"));
        this.parameter.setToken(JSONObject.parseObject(text).getString("token").replaceAll("=", "%3D"));
//        System.out.println(sessionKey);
//        System.out.println(token);
    }

    @Override
    public Parameter resultsOf() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
        openUrl();
        if (page.getTitleText().equals("访问异常")) {
            this.codeO.enterCode();
        }
        getSession_Token();
        @SuppressWarnings("unchecked")
        List<HtmlElement> byXPath = (List<HtmlElement>) page
                .getByXPath("/html/body/div[7]/div[2]/div[1]/div[4]/div[1]/a");
        int pageCount = 0;
        for (int i = byXPath.size() - 1; i < byXPath.size();) {
            try {
                pageCount = Integer.parseInt(byXPath.get(i).asText());
                break;
            } catch (Exception e) {
                i--;
            }
        }
        webClient.addRequestHeader("Host", "www.tianxun.com");
        webClient.addRequestHeader("Referer", "http://www.tianxun.com/");
//        webClient.addRequestHeader("X-Distil-Ajax","cvruvdyucway");
//        webClient.addRequestHeader("X-Distil-Ajax","");
//        webClient.addRequestHeader("X-Requested-With", "XMLHttpRequest");
        for (int i = 1; i <= (pageCount == 0 ? Integer.MAX_VALUE : pageCount); i++) {
            if (page.getTitleText().equals("访问异常")) {
                this.codeO.enterCode();
            }
            String rurl = "http://www.tianxun.com/flight/ajax_intl_list_v3.php?sessionKey="
                    + this.parameter.getSessionKey() + "&token=" + this.parameter.getToken() + "&page=" + i
                    + "&tripType=" + this.parameter.getTripType().getAbbreviations() + "&sort="
                    + this.parameter.getSort() + "&departDate=" + this.parameter.getDepartDate() + "&returnDate="
                    + this.parameter.getReturnDate() + "&_=" + System.currentTimeMillis();
            log.info("pageCount:" + i + " " + rurl);
            
            page = webClient.getPage(rurl);
//            log.info(i + ":" + page.asXml());
            JSONObject obj = JSONObject.parseObject(page.asText());
            if (obj.containsKey("error")) {
//                getSession_Token();
//                i--;
                break;
            } else {
                this.parameter.setResultS(obj);
            }
        }

        close();
        return this.parameter;
    }

    @Override
    public void close() {
        webClient.closeAllWindows();
    }

    @Override
    public WebSite setProxy(String proxyHost, int proxyPort, String username, String password) {
        proxy = new ProxyOneself(proxyHost, proxyPort, username, password);
        // 设置代理
        webClient = new WebClient(BrowserVersion.INTERNET_EXPLORER_11, proxyHost, proxyPort);
        if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) {
            final DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
                    .getCredentialsProvider();
            credentialsProvider.addCredentials(username, password);
        }
        return this;
    }

    @Override
    public WebSite setProxy(String proxyHost, int proxyPort) {
        // 设置代理
        setProxy(proxyHost, proxyPort, null, null);
        return this;
    }

    @Override
    public WebSite openUrl() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
        webClient.setAjaxController(new NicelyResynchronizingAjaxController());
        webClient.setJavaScriptTimeout(50000);
        webClient.waitForBackgroundJavaScript(50000);
        webClient.setRefreshHandler(new ThreadedRefreshHandler());
        webClient.setCssErrorHandler(new SilentCssErrorHandler());
        webClient.getOptions().setJavaScriptEnabled(true);
        webClient.getOptions().setCssEnabled(true);
        webClient.getOptions().setRedirectEnabled(true);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        webClient.getOptions().setTimeout(50000);
        url = "http://www.tianxun.com/intl-" + this.parameter.getTripType().getFullName() + "-"
                + this.parameter.getDepCityCode() + "-" + this.parameter.getDstCityCode() + ".html?depdate="
                + this.parameter.getDepartDate() + "&rtndate=" + this.parameter.getReturnDate()
                + "&cabin=Economy&adult=1&child=0&infant=0";
        log.info("打开访问地址." + url);
        // 打开地址
//        webClient.getPage("http://www.tianxun.com/");
        Page pageTmp;
        do {
            pageTmp = webClient.getPage(url);
        } while (!pageTmp.isHtmlPage());
        page = (HtmlPage) pageTmp;
        return this;
    }

}

interface Code {
    void enterCode() throws IOException;
}
